home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 176-200 / disk_191 / blk / blk.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  40KB  |  1,752 lines

  1. /*
  2.  *     blk    - Automatic Requester formatter and generator.
  3.  *
  4.  * Reads a requester description and formats graphically then generates the
  5.  * appropriate C-code to specify the requester.  See the examples and the
  6.  * documentaion for using the program.
  7.  *
  8.  * Process flow:  Box structure read by recursive-descent.  Boxes formatted
  9.  * and layed-out, also recursively.  Borders generated and optimized into a
  10.  * minimum set of Border structs.  Working preview displayed for fiddling
  11.  * with.  Output declarations written to file.
  12.  *
  13.  * Problems:  In a nutshell -- error recovery.  It doesn't do too well if
  14.  * it runs out of memory, especially in the Border optimization code.
  15.  * Also, the user error messages on parse errors could be much better --
  16.  * like giving line number or a sample of the code at that point -- something
  17.  * that would give a clue as to what went wrong.  Other than that, it's
  18.  * pretty good.
  19.  *
  20.  * Differences from version 1:  Version 1 was distributed on a Fish disk
  21.  * and was a real hack.  This version supports a 'C'-like preprocessor 
  22.  * with #include's and #define's and macros with arguments.  This makes
  23.  * the Requester source files look much nicer since the underlying 
  24.  * grammar is so unreadable.  
  25.  *
  26.  * Disclaimer: This is a tool I hacked up for my own use in creating requesters
  27.  * for Modeler 3D.  It works for me, but I make no claim as to the robustness
  28.  * or other quality of the code.  It's not mouse-driven, but it's such a
  29.  * useful tool that it's worth learning anyway.  Besides, you can put it in
  30.  * your makefile's and have it work just like any other compiler.
  31.  *
  32.  * I'm making this available as a service to Amiga developers.  You are
  33.  * encouraged to enhance or modify as you need to make it more useful for
  34.  * your own purposes.  If you make any changes that make this a better
  35.  * general-purpose tool, let me know about them.
  36.  *
  37.  *    Stuart Ferguson        1/89
  38.  *    (shf@well.UUCP)
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <functions.h>
  43. #include <exec/types.h>
  44. #include <intuition/intuition.h>
  45.  
  46. /* STD.H is my collection of useful macros.
  47.  */
  48. #include "std.h"
  49.  
  50. /* LEX.H is the lexical analysis defines.
  51.  */
  52. #include "lex.h"
  53.  
  54.  
  55. #define abs(x)          ((x)<0 ? -(x) : (x))
  56.  
  57. /* Size of font for text boxes (fixed width assumed).
  58.  */
  59. #define FONTWIDTH    8
  60. #define FONTHEIGHT    8
  61.  
  62. /* Box types
  63.  */
  64. #define HBOX    1
  65. #define VBOX    2
  66. #define FILL    3
  67. #define BLOK    4
  68. #define TEXT    5
  69. #define HRULE    6
  70. #define VRULE    7
  71.  
  72. /*
  73.  * Extended Gadget structure to hold an optional special gadget ID name
  74.  * and the parent box for this gadget.
  75.  */
  76. struct SuperGadget {
  77.     struct Gadget    g;
  78.     struct Box    *box;
  79.     char        *gnam;
  80. };
  81.  
  82. /*
  83.  * A requester is constructed from a tree of Boxes.  Boxes are arranged in a
  84.  * binary tree, one subtree is what is inside the Box (sub), the other is the
  85.  * remaining Boxes at the same level (next). 
  86.  */
  87. typedef struct Box {
  88.     struct SuperGadget    *gad;    /* gadget - if any */
  89.     struct Box     *next, *sub;    /* binary tree links */
  90.     short           type,        /* box type - possibilities above */
  91.                     col;    /* color - for borders and text */
  92.     short           xs, ys,    /* box size (x,y) */
  93.                     x, y,    /* box position (x,y) */
  94.                     nfil;    /* number of filers inside this box */
  95.     char           *val;        /* string for TEXT boxes */
  96. };
  97.  
  98.  
  99. /* GLOBAL */
  100.  
  101. int        infoLevel = 1,    /* degree of verbosity (0=quiet, 
  102.                  * 1=normal, 2=verbose)
  103.                  */
  104.         printBoxes = 0,    /* printout flag (false normally) */
  105.         showPreview;    /* preview flag (depends on whether there's
  106.                  * an output file and on the '-d' flag.
  107.                  */
  108. char           *globStr = "static ";    /* structures normally static */
  109.  
  110. FILE           *file;        /* output file */
  111. char           *base;        /* base name */
  112. short           def_bcol = 1,     /* default border and */
  113.         def_tcol = 1;    /* text colors */
  114.  
  115. /* String pointer ID's returned from the lexer.
  116.  */
  117. char           *fill_pstr, *tbox_pstr, *hbox_pstr, *vbox_pstr,
  118.            *blok_pstr, *s_pstr, *p_pstr, *pv_pstr, *ph_pstr;
  119.  
  120. /* The Requester structures, the lists of parts and the guy itself.
  121.  */
  122. struct Border    *blst = NULL;    /* list header for border structs */
  123. struct IntuiText *itlst = NULL;    /* list header for text structs */
  124. struct Gadget    *glst = NULL;    /* list header for gadgets */
  125.  
  126. #define LATER    0
  127.  
  128. struct Requester mreq = {
  129.     NULL,5,5,LATER,LATER,0,0,LATER,LATER,LATER,
  130.     0,0,NULL,{NULL},NULL,NULL,{NULL}
  131. };
  132.  
  133. /*
  134.  * Generic templates for creating Intuition structures.
  135.  */
  136. struct Border
  137.     generic_border = {0, 0, LATER, 0, JAM1, LATER, LATER, LATER};
  138. struct Gadget
  139.     generic_gadget = {
  140.         LATER, LATER, LATER, LATER, LATER,
  141.         GADGHCOMP,RELVERIFY,BOOLGADGET|REQGADGET,
  142.         LATER, NULL, LATER, 0, LATER, LATER, NULL
  143.     };
  144. struct IntuiText
  145.     generic_itext = {LATER, 0, JAM2, LATER, LATER, LATER, LATER, LATER};
  146. struct StringInfo
  147.     generic_sinfo = {LATER, NULL, 0, LATER, 0};
  148. struct PropInfo
  149.     generic_pinfo = {AUTOKNOB|PROPBORDERLESS,0x8000,0x8000,0x8000,0x8000};
  150.  
  151. /* Two macros to extract GadgetType info from a Gadget structure.
  152.  */
  153. #define GADGETTYPEBITS    (~GADGETTYPE)
  154. #define GTYPE(g)    (((g)->GadgetType)&GADGETTYPEBITS)
  155.  
  156. /*
  157.  * The preview window.
  158.  */
  159. struct NewWindow nwin = {
  160.     0, 0, 300, 150, -1, -1,
  161.     CLOSEWINDOW | REQCLEAR | MOUSEMOVE | GADGETDOWN | GADGETUP | VANILLAKEY,
  162.     WINDOWDEPTH | WINDOWDRAG,
  163.     NULL, NULL, (UBYTE *) "Preview", NULL,
  164.     NULL, 0, 0, 0, 0, WBENCHSCREEN
  165. };
  166.  
  167. struct IntuitionBase *IntuitionBase;
  168.  
  169.  
  170. struct Box * ReadBoxList ();
  171. short Layin ();
  172. char * IMClass ();
  173.  
  174. /* Lexer interface functions.
  175.  */
  176. char * FindString ();
  177. short NextToken ();
  178.  
  179.  
  180. /*
  181.  * Returns a new, initialized Box struct.
  182.  */
  183. struct Box * NewBox (type)
  184.     short           type;
  185. {
  186.     struct Box     *b;
  187.  
  188.     if (!(b = NEW (struct Box))) {
  189.         MemError ();
  190.         return NULL;
  191.     }
  192.     b->type = type;
  193.     b->nfil = 0;
  194.     b->gad = NULL;
  195.     b->val = NULL;
  196.     b->next = b->sub = NULL;
  197.     return b;
  198. }
  199.  
  200.  
  201. /*
  202.  * Recursively frees Box tree.
  203.  */
  204. FreeBox (box)
  205.     struct Box *box;
  206. {
  207.     register struct Gadget    *g;
  208.     register struct StringInfo *si;
  209.  
  210.     if (!box) return;
  211.  
  212.     FreeBox (box->sub);
  213.     FreeBox (box->next);
  214.  
  215.     if (g = (struct Gadget *) box->gad) {
  216.         if (GTYPE(g) == STRGADGET) {
  217.             si = (struct StringInfo *) g->SpecialInfo;
  218.             FREE_X (si, struct StringInfo, si->MaxChars);
  219.         } else if (GTYPE(g) == PROPGADGET) {
  220.             FREE (g->SpecialInfo, struct PropInfo);
  221.             FREE (g->GadgetRender, struct Image);
  222.         }
  223.         FREE (g, struct SuperGadget);
  224.     }
  225.     FREI (box);
  226. }
  227.  
  228.  
  229. /*
  230.  * Recursively examine all nodes of Box tree and allocate Border structs for
  231.  * all the HRULE and VRULE boxes.  Adds new Borders to the main list. 
  232.  * Returns 0 for failure, 1 for sucess.
  233.  */
  234. int CreateBorder (box)
  235.     register struct Box    *box;
  236. {
  237.     register struct Border *bd;
  238.  
  239.     if (!box) return 1;
  240.  
  241.     if (box->type == HRULE || box->type == VRULE) {
  242.         if (!(bd = NEW (struct Border))) {
  243.             MemError ();
  244.             FreeBorder ();
  245.             return 0;
  246.         }
  247.         *bd = generic_border;
  248.         bd->FrontPen = box->col;
  249.         bd->Count = 2;
  250.         if (!(bd->XY = NEW_N (SHORT, 4))) {
  251.             MemError ();
  252.             FREI (bd);
  253.             FreeBorder ();
  254.             return 0;
  255.         }
  256.         bd->XY[0] = bd->XY[2] = box->x;
  257.         bd->XY[1] = bd->XY[3] = box->y;
  258.         if (box->type == HRULE) bd->XY[2] += box->xs - 1;
  259.           else bd->XY[3] += box->ys - 1;
  260.  
  261.         bd->NextBorder = blst;
  262.         blst = bd;
  263.     }
  264.     if (!CreateBorder (box->sub)) return 0;
  265.     return (CreateBorder (box->next));
  266. }
  267.  
  268.  
  269. /*
  270.  * Frees all Border structs in main Border list.
  271.  */
  272. FreeBorder ()
  273. {
  274.     register struct Border *b, *nxt;
  275.  
  276.     for (b = blst; b; b = nxt) {
  277.         nxt = b->NextBorder;
  278.         FREE_N (b->XY, SHORT, b->Count * 2);
  279.         FREI (b);
  280.     }
  281.     blst = NULL;
  282. }
  283.  
  284.  
  285. /*
  286.  * Recursively examine all nodes of Box tree and allocate IntuiText structs
  287.  * for TEXT boxes that are not string gadgets.  Adds new Borders to the main
  288.  * list.  Returns 1 for sucess, 0 for failure.
  289.  */
  290. int CreateIText (box)
  291.     register struct Box     *box;
  292. {
  293.     struct IntuiText    *it;
  294.  
  295.     if (!box) return 1;
  296.  
  297.     /*
  298.      * "box->val" may have been zero-ed by a string gadget grabbing
  299.      * that text.  If so, this is not an IntuiText.
  300.      */
  301.     if (box->type == TEXT && box->val) {
  302.         if (!(it = NEW(struct IntuiText))) {
  303.             MemError ();
  304.             FreeIText ();
  305.             return 0;
  306.         }
  307.         *it = generic_itext;
  308.         it->IText = (UBYTE *) box->val;
  309.         it->LeftEdge = box->x;
  310.         it->TopEdge = box->y;
  311.         it->FrontPen = box->col;
  312.         it->NextText = itlst;
  313.         itlst = it;
  314.     }
  315.     if (!CreateIText (box->sub)) return 0;
  316.     return (CreateIText (box->next));
  317. }
  318.  
  319.  
  320. /*
  321.  * Frees all IntuiText structs in the main list.  (No need to free the
  322.  * text itself since that is managed by the lexer.)
  323.  */
  324. FreeIText ()
  325. {
  326.     register struct IntuiText *it, *nxt;
  327.  
  328.     for (it = itlst; it; it = nxt) {
  329.         nxt = it->NextText;
  330.         FREI (it);
  331.     }
  332.     itlst = NULL;
  333. }
  334.  
  335.  
  336. /*
  337.  * First pass at merging redundant Borders:  Examines all the Borders in
  338.  * the list for adjacency.  Any borders that could use the same set of
  339.  * polyline commands are merged into a single struct. 
  340.  */
  341. MergeBorders ()
  342. {
  343.     register struct Border *a, *b;
  344.     short           i0, i1, x, y, *xy, j;
  345.     register short  i, ac, bc, merge;
  346.  
  347.     do {
  348.         merge = -1;
  349.         /*
  350.          * Examine all pairs of borders, "a" and "b", that
  351.          * are drawn with the same color, seaching for a pair
  352.          * that can be merged.  When loop exits with merge=-1,
  353.          * all pairs have been merged.
  354.          */
  355.         for (a = blst; a; a = a->NextBorder) {
  356.             for (b = a->NextBorder; b; b = b->NextBorder) {
  357.                 if (a->FrontPen != b->FrontPen) continue;
  358.  
  359.                 /*
  360.                  * Examine the 4 pairs of endpoints of each
  361.                  * polyline to see if any are adjacent to
  362.                  * each other.  If any are found, the pairs
  363.                  * located are encoded into "merge" and
  364.                  * the search loop exits.
  365.                  */
  366.                 ac = a->Count;
  367.                 bc = b->Count;
  368.                 for (i0 = 0; i0 < 2; i0++)
  369.                     for (i1 = 0; i1 < 2; i1++) {
  370.                         x = a->XY[i0*2 * (ac - 1)]
  371.                           - b->XY[i1*2 * (bc - 1)];
  372.                         y = a->XY[i0*2 * (ac - 1) + 1]
  373.                           - b->XY[i1*2 * (bc - 1) + 1];
  374.                         if (abs (x) + abs (y) == 1)
  375.                             merge = (i0 << 1) + i1;
  376.                     }
  377.                 if (merge != -1)
  378.                     break;
  379.             }
  380.             if (merge != -1)
  381.                 break;
  382.         }
  383.         if (merge == -1) continue;
  384.  
  385.         /*
  386.          * Merging: Create a new polyline data array and move
  387.          * the two parent polylines into the new one, possibly
  388.          * reversing one or both in the process.
  389.          * -- HELP ME:    Is there a nice way out if this
  390.          *        allocation fails...?
  391.          */
  392.         xy = NEW_N (SHORT, (bc + ac) * 2);
  393.         x = ((merge & 2) == 0);        /* x = reverse "a" */
  394.         y = ((merge & 1) == 1);        /* y = reverse "b" */
  395.         j = 0;
  396.         for (i = 0; i < ac; i++) {
  397.             i0 = (x ? ac - 1 - i : i) * 2;
  398.             xy[j++] = a->XY[i0];
  399.             xy[j++] = a->XY[i0 + 1];
  400.         }
  401.         for (i = 0; i < bc; i++) {
  402.             i0 = (y ? bc - 1 - i : i) * 2;
  403.             xy[j++] = b->XY[i0];
  404.             xy[j++] = b->XY[i0 + 1];
  405.         }
  406.  
  407.         /*
  408.          * Set "a" to have the new polyline data array.
  409.          */
  410.         a->Count = j / 2;
  411.         FREE_N (a->XY, SHORT, ac * 2);
  412.         a->XY = xy;
  413.  
  414.         /*
  415.          * Find "b's" predecessor and remove "b" from list.
  416.          */
  417.         for (a = blst; a && a->NextBorder != b; a = a->NextBorder);
  418.         a->NextBorder = b->NextBorder;
  419.         FREE_N (b->XY, SHORT, bc * 2);
  420.         FREE (b, struct Border);
  421.  
  422.     } while (merge != -1);
  423. }
  424.  
  425.  
  426. /*
  427.  * Second pass of Border merging: Eliminates linear segments from all
  428.  * Borders XY lists.  The first pass will create lots of redundant points
  429.  * along linear line segments.  This pass will compress those out.
  430.  */
  431. MergeLinear ()
  432. {
  433.     register struct Border *b;
  434.     register short  i0, i1, i2, k, *xy;
  435.  
  436.     /*
  437.      * Examine all borders with more than 1 line segment.
  438.      */
  439.     for (b = blst; b; b = b->NextBorder) {
  440.         if (b->Count < 3) continue;
  441.  
  442.         /*
  443.          * Scan along the polyline list and compress out linear
  444.          * segments by skiping over them.
  445.          */
  446.         xy = b->XY;
  447.         i0 = 0;
  448.         i1 = 1;
  449.         i2 = 2;
  450.         k = 2;
  451.         while (i2 < b->Count) {
  452.             /*
  453.              * Skip past linear segments. (I.e. find the bend.)
  454.              */
  455.             while (i2 < b->Count &&
  456.                    (xy[i0 * 2] == xy[i1 * 2]
  457.                  && xy[i1 * 2] == xy[i2 * 2] ||
  458.                 xy[i0 * 2 + 1] == xy[i1 * 2 + 1]
  459.                  && xy[i1 * 2 + 1] == xy[i2 * 2 + 1])) {
  460.                 i1++;
  461.                 i2++;
  462.             }
  463.             if (i2 >= b->Count) continue;
  464.  
  465.             /*
  466.              * Move polyline data to itself after skipping.
  467.              */
  468.             xy[k++] = xy[i1 * 2];
  469.             xy[k++] = xy[i1 * 2 + 1];
  470.             i0 = i1;
  471.             i1 = i2;
  472.             i2 = i1 + 1;
  473.         }
  474.         xy[k++] = xy[i1 * 2];
  475.         xy[k++] = xy[i1 * 2 + 1];
  476.  
  477.         k /= 2;
  478.         if (k == b->Count) continue;
  479.  
  480.         /*
  481.          * If this border has gotten shorter, allocate a new
  482.          * array and transfer the new polyline data.
  483.          */
  484.         xy = NEW_N (SHORT, k * 2);
  485.         for (i0 = 0; i0 < k * 2; i0++) xy[i0] = b->XY[i0];
  486.         FREE_N (b->XY, SHORT, b->Count * 2);
  487.         b->XY = xy;
  488.         b->Count = k;
  489.     }
  490. }
  491.  
  492.  
  493. /*
  494.  * Set the XSize and YSize fields for this box and all below.
  495.  */
  496. Format (box)
  497.     struct Box     *box;
  498. {
  499.     struct Box     *b;
  500.     short           mx, my, sx, sy, nf;
  501.  
  502.     ASSERT (box);
  503.  
  504.     /*
  505.      * Deal with the basis (leaf) cases.
  506.      */
  507.     switch (box->type) {
  508.     
  509.         /* Blok and text nodes have fixed, already computed size.
  510.          */
  511.         case BLOK:
  512.         case TEXT:
  513.         return;
  514.  
  515.         /* Fill node has no intrinsic size.
  516.          */
  517.         case FILL:
  518.         box->xs = box->ys = 0;
  519.         box->nfil = 1;
  520.         return;
  521.  
  522.         /* H and VRULES have no intrinsic X or Y size, respectively.
  523.          */
  524.         case HRULE:
  525.         box->xs = 0;
  526.         return;
  527.         case VRULE:
  528.         box->ys = 0;
  529.         return;
  530.     }
  531.  
  532.     /*
  533.      * H and VBOXes are the recursive case.  First format each
  534.      * internal box.
  535.      */
  536.     for (b = box->sub; b; b = b->next) Format (b);
  537.  
  538.     /*
  539.      * Compute total and max sizes in each direction. Total (sx,sy) is sum
  540.      * of all sub-boxes, max (mx,my) is max of sub-boxes. Also inherit
  541.      * filler count.
  542.      */
  543.     my = mx = sx = sy = nf = 0;
  544.     for (b = box->sub; b; b = b->next) {
  545.         sx += b->xs;
  546.         sy += b->ys;
  547.         if (b->type == box->type || b->type == FILL) nf += b->nfil;
  548.         if (b->xs > mx) mx = b->xs;
  549.         if (b->ys > my)    my = b->ys;
  550.     }
  551.     box->nfil = nf;
  552.  
  553.     /*
  554.      * For horizontal boxes, bounding box is sum in x and max in y; for
  555.      * vertical, bouding box is max in x and sum in y.  This is the
  556.      * minimum size of the containing box for the given subboxes.  It
  557.      * may still expand due to fillers.
  558.      */
  559.     if (box->type == HBOX) {
  560.         box->xs = sx;
  561.         box->ys = my;
  562.     } else if (box->type == VBOX) {
  563.         box->xs = mx;
  564.         box->ys = sy;
  565.     }
  566. }
  567.  
  568.  
  569. /*
  570.  * Compute the position of the boxes internal to this box given that this
  571.  * box has correct location.  The box size computed by Format() is a minimum
  572.  * size, "mx" and "my" are the max that the box can be expanded by filler.
  573.  */
  574. Layout (box, mx, my)
  575.     struct Box     *box;
  576.     short           mx, my;
  577. {
  578.     struct Box     *b;
  579.     short           ish, z, nfil;
  580.     long            gap, ifil;
  581.  
  582.     ASSERT (box);
  583.  
  584.     /*
  585.      * Rules fill out to their max possible size.
  586.      */
  587.     if (box->type == HRULE) box->xs = mx;
  588.      else if (box->type == VRULE) box->ys = my;
  589.  
  590.     /*
  591.      * Process only HBOX and VBOX cases recursively.  Any other case (a
  592.      * basis case) has its position set correctly (see assumptions at
  593.      * head of function).
  594.      */
  595.     if (box->type != HBOX && box->type != VBOX) return;
  596.  
  597.     /* Get important values.  Set the "is-hbox" (ish) flag.  Get the
  598.      * current X size for HBOXes or the Y size for VBOXes as "z".
  599.      * "gap" is the differece between the max size and minimum size 
  600.      * given by the Format(), and is how much fillers can expand.
  601.      */
  602.     ish = (box->type == HBOX);
  603.     z = (ish ? box->x : box->y);
  604.     gap = (ish ? mx - box->xs : my - box->ys);
  605.  
  606.     /*
  607.      * Set positions by setting filler sizes.
  608.      */
  609.     ifil = 0;
  610.     Layin (box, &ifil, ish, z, box->nfil, gap);
  611.  
  612.     /* Update box size.  If it had fillers, it got as big as
  613.      * it could.
  614.      */
  615.     if (box->nfil) {
  616.         if (ish) box->xs = mx;
  617.             else box->ys = my;
  618.     }
  619. }
  620.  
  621.  
  622. /*
  623.  * Layout internal boxes.  Having this as a recursive function deals with
  624.  * the case of VBOXes within VBOXes and HBOXes within HBOXes.
  625.  *
  626.  * NOTE: I'd comment this function, but I can't figure it out.  It seems to
  627.  * figure out the horizonal position of each box and update it as it goes
  628.  * along.  It also calls itself when there are nested same-class boxes.
  629.  * Oh well.  There's probably a better way to do it anyway.
  630.  */
  631. short Layin (box, ifil, ish, z, nfil, gap)
  632.     struct Box     *box;
  633.     short          *ifil, ish, z, nfil;
  634.     long            gap;
  635. {
  636.     struct Box     *b;
  637.     short           t;
  638.  
  639.     for (b = box->sub; b; b = b->next) {
  640.         if (ish) {
  641.             b->x = z;
  642.             b->y = box->y;
  643.         } else {
  644.             b->x = box->x;
  645.             b->y = z;
  646.         }
  647.  
  648.         if (b->type == FILL) {
  649.             t = (gap * (*ifil + 1)) / nfil - (gap ** ifil) / nfil;
  650.             (*ifil)++;
  651.             if (ish) b->xs = t;
  652.                 else b->ys = t;
  653.  
  654.         } else if ((ish && b->type == HBOX)
  655.                || (!ish && b->type == VBOX)) {
  656.             if (ish) b->ys = box->ys;
  657.                 else b->xs = box->xs;
  658.             t = Layin (b, ifil, ish, z, nfil, gap) - z;
  659.             if (ish) b->xs = t;
  660.                 else b->ys = t;
  661.  
  662.         } else Layout (b, box->xs, box->ys);
  663.  
  664.         z += (ish ? b->xs : b->ys);
  665.     }
  666.     return z;
  667. }
  668.  
  669.  
  670. /*
  671.  * Use the computed position of the boxes to set the position of
  672.  * the associated gadgets.
  673.  */
  674. PositionGadgets ()
  675. {
  676.     struct Box    *b;
  677.     struct Gadget    *g;
  678.  
  679.     for (g = glst; g; g = g->NextGadget) {
  680.         b = ((struct SuperGadget *) g)->box;
  681.         g->LeftEdge = b->x;
  682.         g->TopEdge = b->y;
  683.         g->Width = b->xs;
  684.         g->Height = b->ys;
  685.     }
  686. }
  687.  
  688.  
  689. /*
  690.  * Returns pointer to string containing box type name for printout.
  691.  */
  692. char * BoxType (typ)
  693.     short           typ;
  694. {
  695.     switch (typ) {
  696.         case HBOX:    return ("HBOX");
  697.         case VBOX:    return ("VBOX");
  698.         case BLOK:    return ("BLOK");
  699.         case TEXT:    return ("TEXT");
  700.         case FILL:    return ("FILL");
  701.         case HRULE:    return ("HRULE");
  702.         case VRULE:    return ("VRULE");
  703.     }
  704. }
  705.  
  706.  
  707. /*
  708.  * Recursively prints this box and all its contents.
  709.  */
  710. PrintBox (box, lev)
  711.     struct Box     *box;
  712.     short           lev;
  713. {
  714.     int             i;
  715.  
  716.     if (!box) return;
  717.  
  718.     for (i = 0; i < lev; i++) printf ("  ");
  719.  
  720.     printf ("%s (%d,%d) %dx%d", BoxType (box->type),
  721.         box->x, box->y, box->xs, box->ys);
  722.     if (box->type == TEXT)    printf (" <%s>", box->val);
  723.     if (box->gad)         printf (" [gadget]");
  724.     printf ("\n");
  725.  
  726.     PrintBox (box->sub, lev + 1);
  727.     PrintBox (box->next, lev);
  728. }
  729.  
  730.  
  731.  
  732. /*
  733.  * ==== INPUT SECTION ====
  734.  *
  735.  * File input uses the "lex" front-end for macro processing.  Main entry
  736.  * points for this package are the NextToken() and Backspace() functions.
  737.  * NextToken() returns the code for the next lexical item in the input 
  738.  * stream and sets a buffer pointer to point to its value.  Backspace()
  739.  * resets the lex package to re-read the last token read, so that the
  740.  * file is effectively backspaced one token.  FindString() is also used
  741.  * to get the unique identifer pointer for a string from the hash table.
  742.  */
  743.  
  744.  
  745. /*
  746.  * Read a number if there is one.  Otherwise return false and don't
  747.  * change n's value.
  748.  */
  749. BOOL Qnum (n, radix)
  750.     short          *n, radix;
  751. {
  752.     short           i = 0, tok;
  753.     char           *buf;
  754.  
  755.     tok = NextToken (&buf);
  756.     if (tok != RT_NUM) {
  757.         Backspace ();
  758.         return 0;
  759.     }
  760.     for (; *buf >= '0' && *buf <= '9'; buf++) {
  761.         i = i * radix + (*buf - '0');
  762.     }
  763.     *n = i;
  764.     return 1;
  765. }
  766.  
  767.  
  768. /*
  769.  * Reads a double-quoted string like
  770.  *    "stuff"
  771.  * from the file.  Returns pointer to the string contents. 
  772.  */
  773. char * ReadString ()
  774. {
  775.     short           tok;
  776.     char           *buf;
  777.  
  778.     tok = NextToken (&buf);
  779.     if (tok != RT_STR) {
  780.         fprintf (stderr, "String not found.\n");
  781.         Backspace ();
  782.         return NULL;
  783.     }
  784.     return buf;
  785. }
  786.  
  787.  
  788. /*
  789.  * Read gadget ID of the form 
  790.  *    :number
  791.  * if there is one.  Read as hex.  If there is one, create a new
  792.  * SuperGadget structure and add to the main gadget list.
  793.  */
  794. struct SuperGadget * ReadOptGadget (box)
  795.     struct Box *box;
  796. {
  797.     struct SuperGadget *sg;
  798.     short           tok, id;
  799.     char           *buf;
  800.  
  801.     tok = NextToken (&buf);
  802.     if (tok != RT_CHR || *buf != ':') {
  803.         Backspace ();
  804.         return NULL;
  805.     }
  806.     if (!Qnum (&id, 16)) {
  807.         fprintf (stderr, "Error reading gadget ID number\n");
  808.         return NULL;
  809.     }
  810.  
  811.     if (!(sg = NEW (struct SuperGadget))) {
  812.         MemError ();
  813.         return NULL;
  814.     }
  815.     sg->g = generic_gadget;
  816.     sg->gnam = NULL;
  817.     sg->box = box;
  818.     sg->g.GadgetID = id;
  819.     sg->g.NextGadget = glst;
  820.     glst = (struct Gadget *) sg;
  821.     return sg;
  822. }
  823.  
  824.  
  825. /*
  826.  * Get a box from the open file.  Boxes are either single tokens ("f"
  827.  * for FILL box, "-" and "|" for ordinary rules) or is a
  828.  * composite of the form "("type data")".  Type can be "h" for HBOX,
  829.  * "v" for VBOX, "b" for BLOK, "t" for TEXT, or "-" and "|" again for 
  830.  * special rules.
  831.  *
  832.  * If there isn't a box here, ReadBox() returns NULL with the lexical
  833.  * stream positioned back to read whatever was really there.
  834.  */
  835. struct Box * ReadBox ()
  836. {
  837.     short           tok, i;
  838.     char           *buf, c;
  839.     struct Box     *b;
  840.  
  841.     tok = NextToken (&buf);
  842.  
  843.     if (tok == RT_ID && buf == fill_pstr) return NewBox (FILL);
  844.  
  845.     if (tok != RT_CHR) {
  846.         Backspace ();
  847.         return NULL;
  848.     }
  849.  
  850.     c = *buf;
  851.     if (c == '-') {
  852.         if (!(b = NewBox (HRULE))) return NULL;
  853.         b->ys = 1;
  854.         b->col = def_bcol;
  855.         return b;
  856.     }
  857.     if (c == '|') {
  858.         if (!(b = NewBox (VRULE))) return NULL;
  859.         b->xs = 1;
  860.         b->col = def_bcol;
  861.         return b;
  862.     }
  863.     if (c != '(') {
  864.         Backspace ();
  865.         return NULL;
  866.     }
  867.  
  868.     /*
  869.      * Decode the value inside the '('.
  870.      */
  871.     tok = NextToken (&buf);
  872.     c = *buf;
  873.     if (tok == RT_ID)
  874.         if (buf == hbox_pstr) {
  875.             if (!(b = NewBox (HBOX))) return NULL;
  876.             b->sub = ReadBoxList ();
  877.         } else if (buf == vbox_pstr) {
  878.             if (!(b = NewBox (VBOX))) return NULL;
  879.             b->sub = ReadBoxList ();
  880.         } else if (buf == tbox_pstr) {
  881.             if (!(b = NewBox (TEXT))) return NULL;
  882.             b->col = def_tcol;
  883.             Qnum (&b->col, 10);
  884.             if (!(b->val = ReadString ())) {
  885.                 FreeBox (b);
  886.                 return NULL;
  887.             }
  888.             b->xs = strlen (b->val) * FONTWIDTH;
  889.             b->ys = FONTHEIGHT;
  890.         } else if (buf == blok_pstr) {
  891.             if (!(b = NewBox (BLOK))) return NULL;
  892.             i = Qnum (&b->xs, 10);
  893.             i &= Qnum (&b->ys, 10);
  894.             if (!i) {
  895.                 fprintf (stderr, "Block needs X and Y sizes\n");
  896.                 return NULL;
  897.             }
  898.         } else {
  899.             fprintf (stderr, "Unrecognized box type <%s>\n", buf);
  900.             return NULL;
  901.         }
  902.     else if (tok == RT_CHR)
  903.         switch (c) {
  904.             case '-':
  905.             if (!(b = NewBox (HRULE))) return NULL;
  906.             if (!Qnum (&b->ys, 10)) {
  907.                 fprintf (stderr, "Bad hrule structure.\n");
  908.                 return NULL;
  909.             }
  910.             b->col = def_bcol;
  911.             Qnum (&b->col, 10);
  912.             break;
  913.             case '|':
  914.             if (!(b = NewBox (VRULE))) return NULL;
  915.             if (!Qnum (&b->xs, 10)) {
  916.                 fprintf (stderr, "Bad vrule structure\n");
  917.                 return NULL;
  918.             }
  919.             b->col = def_bcol;
  920.             Qnum (&b->col, 10);
  921.             break;
  922.             default:
  923.             fprintf (stderr, "Unrecognized box type <%c>\n", c);
  924.             return NULL;
  925.         }
  926.     else {
  927.         fprintf (stderr, "Unrecognized box type <%s>\n", buf);
  928.         return NULL;
  929.     }
  930.     /*
  931.      * Pick up the closing ')'.
  932.      */
  933.     tok = NextToken (&buf);
  934.     if (tok != RT_CHR || *buf != ')') {
  935.         fprintf (stderr, "Parse error - expected ')' !\n");
  936.         FreeBox (b);
  937.         return NULL;
  938.     }
  939.  
  940.     /*
  941.      * Read the optional Gadget for this box (as ":id").
  942.      */
  943.     b->gad = ReadOptGadget (b);
  944.     return b;
  945. }
  946.  
  947.  
  948. /*
  949.  * Read a list of boxes from the file stream.  Recursive: read a box,
  950.  * then read a list. 
  951.  */
  952. struct Box * ReadBoxList ()
  953. {
  954.     struct Box      *b;
  955.  
  956.     b = ReadBox ();
  957.     if (!b) return NULL;
  958.  
  959.     b->next = ReadBoxList ();
  960.     return b;
  961. }
  962.  
  963.  
  964. /*
  965.  * Create a new StringInfo struct and initialize to point to the 
  966.  * given string buffer.  Allocates space for the buffer along with
  967.  * the info struct itself (NEW_X).  Removes trailing spaces.
  968.  */
  969. APTR NewStrInfo (buf)
  970.     char *buf;
  971. {
  972.     struct StringInfo    *si;
  973.     short            i;
  974.     char            *str;
  975.  
  976.     i = strlen (buf) + 1;
  977.     if (!(si = NEW_X (struct StringInfo, i))) {
  978.         MemError ();
  979.         return NULL;
  980.     }
  981.     *si = generic_sinfo;
  982.     si->Buffer = (UBYTE *) (str = (char *) (si+1));
  983.     si->MaxChars = i;
  984.     strcpy (str, buf);
  985.     for (i -= 2; i>=0 && str[i] == ' '; i--) str[i] = 0;
  986.     return (APTR) si;
  987. }
  988.  
  989.  
  990. /* Create new PropInfo struct.  Set the free motion flag based on the
  991.  * id for this gadget "pv" = vert prop, "ph" = horiz prop, "p" = h+v prop.
  992.  */
  993. APTR NewPropInfo (id)
  994.     char *id;
  995. {
  996.     register struct PropInfo    *pi;
  997.  
  998.     if (!(pi = NEW (struct PropInfo))) {
  999.         MemError ();
  1000.         return NULL;
  1001.     }
  1002.     *pi = generic_pinfo;
  1003.     if (id == p_pstr || id == pv_pstr) pi->Flags |= FREEVERT;
  1004.     if (id == p_pstr || id == ph_pstr) pi->Flags |= FREEHORIZ;
  1005.     return (APTR) pi;
  1006. }
  1007.  
  1008.  
  1009. /*
  1010.  * Reads the list of gadget info from the end of the file.  Reads as much
  1011.  * as there is.  Format is:
  1012.  *    number {s|p|pv|ph} {:string} string
  1013.  * stuff in {}'s is optional.  Each entry gives extra info for the numbered
  1014.  * gadget.  {s|p} is string or prop flag.  {:string} is the optional named
  1015.  * value rather than just the nubmer.  The last string is the gadget flags.
  1016.  * Each set of info gets added to the corresponding gadget structure in
  1017.  * the main list.
  1018.  */
  1019. ReadGadInfo ()
  1020. {
  1021.     struct Gadget  *g;
  1022.     struct Box     *box;
  1023.     short           tok;
  1024.     char           *buf, c, *actf;
  1025.     short           i;
  1026.     USHORT        flag;
  1027.  
  1028.     while (Qnum (&i, 16)) {
  1029.         /*
  1030.          * Locate the gadget in question and it's associated box.
  1031.          */
  1032.         for (g = glst; g; g = g->NextGadget)
  1033.             if (g->GadgetID == i) break;
  1034.         if (!g) {
  1035.             fprintf (stderr, "Unknown gadget ID: %x\n", i);
  1036.             continue;
  1037.         }
  1038.         box = ((struct SuperGadget *) g)->box;
  1039.  
  1040.         /* Get the optional string or prop flag.
  1041.          */
  1042.         tok = NextToken (&buf);
  1043.         if (tok == RT_ID) {
  1044.             if (buf == s_pstr) {
  1045.                 g->GadgetType &= ~GADGETTYPEBITS;
  1046.                 g->GadgetType |= STRGADGET;
  1047.                 if (!(g->SpecialInfo = NewStrInfo (box->val)))
  1048.                     return;
  1049.                 box->val = NULL;
  1050.             } else if (buf == p_pstr
  1051.                 || buf == ph_pstr
  1052.                 || buf == pv_pstr) {
  1053.                 g->GadgetType &= ~GADGETTYPEBITS;
  1054.                 g->GadgetType |= PROPGADGET;
  1055.                 if (!(g->SpecialInfo = NewPropInfo (buf)))
  1056.                     return;
  1057.                 if (!(g->GadgetRender =
  1058.                     (APTR) NEW (struct Image))) {
  1059.                     MemError ();
  1060.                     FREE (g->SpecialInfo, struct PropInfo);
  1061.                     return;
  1062.                 }
  1063.             } else {
  1064.                 fprintf (stderr,
  1065.                     "Expected \"s\" or \"p\": <%s>\n", buf);
  1066.                 break;
  1067.             }
  1068.             tok = NextToken (&buf);
  1069.         }
  1070.  
  1071.         /* Get optional gadget ID name string.
  1072.          */
  1073.         if (tok == RT_CHR && *buf == ':') {
  1074.             ((struct SuperGadget *) g)->gnam = ReadString ();
  1075.             tok = NextToken (&buf);
  1076.         }
  1077.         Backspace ();
  1078.  
  1079.         /* Get and process required activation flags string.
  1080.          */
  1081.         actf = ReadString ();
  1082.         g->Activation &= ~RELVERIFY;
  1083.         for (; *actf; actf++) {
  1084.             switch (*actf) {
  1085.                 case 'B':
  1086.                 g->Flags &= ~GADGHIGHBITS;
  1087.                 g->Flags |= GADGHBOX;
  1088.                 flag = 0;
  1089.                 break;
  1090.                 case 't':
  1091.                 flag = TOGGLESELECT;
  1092.                 break;
  1093.                 case 'v':
  1094.                 flag = RELVERIFY;
  1095.                 break;
  1096.                 case 'e':
  1097.                 flag = ENDGADGET;
  1098.                 break;
  1099.                 case 'i':
  1100.                 flag = GADGIMMEDIATE;
  1101.                 break;
  1102.                 case 'c':
  1103.                 flag = STRINGCENTER;
  1104.                 break;
  1105.                 case 'f':
  1106.                 flag = FOLLOWMOUSE;
  1107.                 break;
  1108.             }
  1109.             g->Activation |= flag;
  1110.         }
  1111.     }
  1112. }
  1113.  
  1114.  
  1115. /*
  1116.  * Get values for the identifier strings from the lexical analyzer.
  1117.  * The lexer will return the same pointer for any identifier which
  1118.  * matches.
  1119.  */
  1120. AssignStrings ()
  1121. {
  1122.     fill_pstr = FindString ("f");
  1123.     hbox_pstr = FindString ("h");
  1124.     vbox_pstr = FindString ("v");
  1125.     tbox_pstr = FindString ("t");
  1126.     blok_pstr = FindString ("b");
  1127.     s_pstr = FindString ("s");
  1128.     p_pstr = FindString ("p");
  1129.     ph_pstr = FindString ("ph");
  1130.     pv_pstr = FindString ("pv");
  1131. }
  1132.  
  1133.  
  1134. /*
  1135.  * To read file: open, read base name, read optional default border and text
  1136.  * colors, read a box (a BIG box), read gadget info blocks, close.
  1137.  */
  1138. struct Box * ReadFile ()
  1139. {
  1140.     struct Box     *box;
  1141.     short           i, tok;
  1142.     char           *buf;
  1143.  
  1144.     AssignStrings ();
  1145.     tok = NextToken (&base);
  1146.     if (tok != RT_ID) {
  1147.         fprintf (stderr, "Cannot find base name\n");
  1148.         return NULL;
  1149.     }
  1150.     Qnum (&def_bcol, 10);
  1151.     Qnum (&def_tcol, 10);
  1152.  
  1153.     if (infoLevel > 1) printf ("base name: \"%s\"\ndefault border color:"
  1154.         " %d\ndefault text color: %d\n", base, def_bcol, def_tcol);
  1155.  
  1156.     box = ReadBox ();
  1157.     ReadGadInfo ();
  1158.  
  1159.     /*
  1160.      * Make sure we're at the end of the file to make the
  1161.      * lexer happy.  Print up to 10 error messages unless there
  1162.      * is no box from the previous call in which case there's something
  1163.      * wrong anyway.  (Unless in verbose mode, then show 'em all.)
  1164.      */
  1165.     i = ((box || infoLevel > 1) ? 10 : 0);
  1166.     while (NextToken (&buf) != RT_EOF) {
  1167.         if (i) {
  1168.             fprintf (stderr,
  1169.                 "Token found after end of data: <%s>\n", buf);
  1170.             if (!--i) fprintf (stderr, "... etc.\n");
  1171.         }
  1172.     }
  1173.  
  1174.     return box;
  1175. }
  1176.  
  1177.  
  1178. /*
  1179.  * ====  OUTPUT SECTION  ====
  1180.  *
  1181.  * Dumps structures created during the input and resolution phases of
  1182.  * the processing.  Just takes a pointer to a Requester in WriteRequester()
  1183.  * and dumps the related structures as well.
  1184.  */
  1185.  
  1186. /*
  1187.  * Write string info and buffer declarations from string gadgets
  1188.  * (if any).
  1189.  */
  1190. WriteStrGad (glist)
  1191.     struct Gadget        *glist;
  1192. {
  1193.     struct Gadget        *g;
  1194.     struct StringInfo    *si;
  1195.     int            i, n;
  1196.  
  1197.     /* Count number of string gadgets.
  1198.      */
  1199.     for (n = 0, g = glist; g; g = g->NextGadget)
  1200.         if (GTYPE(g) == STRGADGET) n++;
  1201.  
  1202.     if (!n) return;
  1203.  
  1204.     /* Write the necessary buffers for the string infos.
  1205.      */
  1206.     fprintf (file, "\n%sUBYTE %s_nbuf[%d][NUMCHR] = {\n\t",
  1207.         globStr, base, n);
  1208.     i = n;
  1209.     for (g = glist; g; g = g->NextGadget) {
  1210.         if (GTYPE(g) != STRGADGET) continue;
  1211.  
  1212.         si = (struct StringInfo *) g->SpecialInfo;
  1213.         fprintf (file, " \"%s\"", si->Buffer);
  1214.         if (--i) fprintf (file, ",");
  1215.     }
  1216.  
  1217.     fprintf (file, "\n};\n\n%sstruct StringInfo %s_sinfo[] = {\n",
  1218.         globStr, base);
  1219.     i = 0;
  1220.     for (g = glist; g; g = g->NextGadget) {
  1221.         if (GTYPE(g) != STRGADGET) continue;
  1222.  
  1223.         si = (struct StringInfo *) g->SpecialInfo;
  1224.         fprintf (file, "\t{&%s_nbuf[%d][0],undo,0,NUMCHR,0}",
  1225.             base, i++);
  1226.         if (--n) fprintf (file, ",");
  1227.         fprintf (file, "\n");
  1228.     }
  1229.     fprintf (file, "};\n");
  1230.  
  1231.     if (infoLevel > 1) printf ("wrote %d StringInfo structs\n", i);
  1232. }
  1233.  
  1234.  
  1235. /*
  1236.  * Write prop info and image declarations for prop gadgets (if any).
  1237.  */
  1238. WritePropGad (glist)
  1239.     struct Gadget        *glist;
  1240. {
  1241.     struct Gadget        *g;
  1242.     struct PropInfo        *pi;
  1243.     int            i, n;
  1244.  
  1245.     /* Count number of prop gadgets.
  1246.      */
  1247.     for (n = 0, g = glist; g; g = g->NextGadget)
  1248.         if (GTYPE(g) == PROPGADGET) n++;
  1249.  
  1250.     if (!n) return;
  1251.  
  1252.     /* Write the necessary images for the autoknobs.
  1253.      */
  1254.     fprintf (file, "\n%sstruct Image %s_pimg[%d];\n", globStr, base, n);
  1255.  
  1256.     /* Write the PropInfo structures themselves.
  1257.      */
  1258.     fprintf (file, "\n%sstruct PropInfo %s_pinfo[] = {\n", globStr, base);
  1259.     i = n;
  1260.     for (g = glist; g; g = g->NextGadget) {
  1261.         if (GTYPE(g) != PROPGADGET) continue;
  1262.  
  1263.         pi = (struct PropInfo *) g->SpecialInfo;
  1264.         fprintf (file, "\t{%u,%u,%u,%u,%u}", pi->Flags,
  1265.             pi->HorizPot, pi->VertPot,
  1266.             pi->HorizBody, pi->VertBody);
  1267.         if (--i) fprintf (file, ",");
  1268.         fprintf (file, "\n");
  1269.     }
  1270.     fprintf (file, "};\n");
  1271.  
  1272.     if (infoLevel > 1) printf ("wrote %d PropInfo structs\n", n);
  1273. }
  1274.  
  1275.  
  1276. /*
  1277.  * Write the gadgets from the main gadget list.  Returns number of
  1278.  * gadgets written.
  1279.  */
  1280. int WriteGadgets (glist)
  1281.     struct Gadget    *glist;
  1282. {
  1283.     struct Gadget    *g;
  1284.     int        k = 1, nimg=0, nprp=0, nstr=0;
  1285.     char        *nam;
  1286.  
  1287.     if (!glist) return 0;
  1288.  
  1289.     WriteStrGad (glist);
  1290.     WritePropGad (glist);
  1291.  
  1292.     fprintf (file, "\n%sstruct Gadget %s_gad[] = {\n", globStr, base);
  1293.  
  1294.     for (g = glist; g; g = g->NextGadget) {
  1295.         if (g->NextGadget)
  1296.             fprintf (file, "\t{&%s_gad[%d]", base, k++);
  1297.         else
  1298.             fprintf (file, "\t{NULL");
  1299.  
  1300.         fprintf (file, ",%d,%d,%d,%d,%u,%u,%u,", g->LeftEdge,
  1301.             g->TopEdge, g->Width, g->Height, g->Flags,
  1302.             g->Activation, g->GadgetType);
  1303.  
  1304.         if (GTYPE(g) == PROPGADGET)
  1305.             fprintf (file, "(APTR)&%s_pimg[%d]", base, nimg++);
  1306.         else
  1307.             fprintf (file, "NULL");
  1308.  
  1309.         fprintf (file, ",\n\t NULL,NULL,0,(APTR)");
  1310.  
  1311.         if (GTYPE(g) == PROPGADGET)
  1312.             fprintf (file, "&%s_pinfo[%d]", base, nprp++);
  1313.         else if (GTYPE(g) == STRGADGET)
  1314.             fprintf (file, "&%s_sinfo[%d]", base, nstr++);
  1315.         else
  1316.             fprintf (file, "NULL");
  1317.  
  1318.         if (nam = ((struct SuperGadget *) g)->gnam)
  1319.             fprintf (file, ",%s", nam);
  1320.         else
  1321.             fprintf (file, ",0x%x", g->GadgetID);
  1322.  
  1323.         if (g->NextGadget)
  1324.             fprintf (file, "},\n");
  1325.         else
  1326.             fprintf (file, "}\n");
  1327.     }
  1328.     fprintf (file, "};\n");
  1329.  
  1330.     if (infoLevel > 1) printf ("wrote %d Gadget structs\n", k);
  1331.     return k;
  1332. }
  1333.  
  1334.  
  1335. /*
  1336.  * Write out list of IntuiText structs for main list.  Returns number
  1337.  * of structures written.
  1338.  */
  1339. int WriteText (tlist)
  1340.     struct IntuiText    *tlist;
  1341. {
  1342.     struct IntuiText    *it;
  1343.     int            k = 1;
  1344.  
  1345.     if (!tlist) return 0;
  1346.  
  1347.     fprintf (file, "\n%sstruct IntuiText %s_txt[] = {\n", globStr, base);
  1348.  
  1349.     for (it = tlist; it; it = it->NextText) {
  1350.         fprintf (file, "\t{%d,%d,%d,%d,%d,&ta,(UBYTE*)\"%s\",",
  1351.             it->FrontPen, it->BackPen, it->DrawMode,
  1352.             it->LeftEdge, it->TopEdge, it->IText);
  1353.         if (it->NextText)
  1354.             fprintf (file, "&%s_txt[%d]},\n", base, k++);
  1355.         else
  1356.             fprintf (file, "NULL},\n");
  1357.     }
  1358.     fprintf (file, "};\n");
  1359.  
  1360.     if (infoLevel > 1) printf ("wrote %d IntuiText structs\n", k);
  1361.     return k;
  1362. }
  1363.  
  1364.  
  1365. /*
  1366.  * Write out list of XY arrays from Border struct main list 
  1367.  */
  1368. WriteBorderXY (lst)
  1369.     struct Border *lst;
  1370. {
  1371.     register struct Border *b;
  1372.     register short  i;
  1373.  
  1374.     fprintf (file, "\n%sshort %s_brd_XY[] = {\n", globStr, base);
  1375.     for (b = lst; b; b = b->NextBorder) {
  1376.         fprintf (file, "\t");
  1377.         for (i = 0; i < b->Count; i++) {
  1378.             fprintf (file, "%d,%d", b->XY[i * 2], b->XY[i * 2 + 1]);
  1379.             if (i != b->Count - 1 || b->NextBorder)
  1380.                 fprintf (file, ", ");
  1381.         }
  1382.         fprintf (file, "\n");
  1383.     }
  1384.     fprintf (file, "};\n");
  1385. }
  1386.  
  1387.  
  1388. /*
  1389.  * Write out list of Border structs from main list.  Returns nubmer of
  1390.  * structures written.
  1391.  */
  1392. int WriteBorder (lst)
  1393.     struct Border *lst;
  1394. {
  1395.     register struct Border *b;
  1396.     register short  i = 0, k = 1;
  1397.  
  1398.     if (!lst) return 0;
  1399.  
  1400.     WriteBorderXY (lst);
  1401.  
  1402.     fprintf (file, "\n%sstruct Border %s_brd[] = {\n", globStr, base);
  1403.     for (b = lst; b; b = b->NextBorder) {
  1404.         fprintf (file, "\t{0,0,%d,0,JAM1,%d,&%s_brd_XY[%d],",
  1405.              b->FrontPen, b->Count, base, i);
  1406.         i += b->Count * 2;
  1407.         if (b->NextBorder)
  1408.             fprintf (file, "&%s_brd[%d]},\n", base, k++);
  1409.         else
  1410.             fprintf (file, "NULL}\n");
  1411.     }
  1412.     fprintf (file, "};\n");
  1413.  
  1414.     if (infoLevel > 1) printf ("wrote %d Border structs\n", k);
  1415.     return k;
  1416. }
  1417.  
  1418.  
  1419. /*
  1420.  * Reverse the gadget list so it will make more sense to the client.
  1421.  * This way they will appear in the arrays in the order that they 
  1422.  * appear in the description file.
  1423.  */
  1424. struct Gadget * ReverseGadList (head)
  1425.     struct Gadget *head;
  1426. {
  1427.     struct Gadget *newhead = NULL, *nxt;
  1428.  
  1429.     for (; head; head = nxt) {
  1430.         nxt = head->NextGadget;
  1431.         head->NextGadget = newhead;
  1432.         newhead = head;
  1433.     }
  1434.     return newhead;
  1435. }
  1436.  
  1437.  
  1438. /*
  1439.  * The main output function.
  1440.  */
  1441. WriteRequester (name, req)
  1442.     char             *name;
  1443.     struct Requester *req;
  1444. {
  1445.     short           i, ng, nt, nb;
  1446.  
  1447.     if (!(file = fopen (name, "w"))) {
  1448.         fprintf (stderr, "Can't open output file\n");
  1449.         return;
  1450.     }
  1451.  
  1452.     req->ReqGadget = ReverseGadList (req->ReqGadget);
  1453.     ng = WriteGadgets (req->ReqGadget);
  1454.     nt = WriteText (req->ReqText);
  1455.     nb = WriteBorder (req->ReqBorder);
  1456.  
  1457.     /*
  1458.      * The requester itself.
  1459.      */
  1460.     fprintf (file, "\n%sstruct Requester %s_req = {\n\
  1461. \tNULL,0,0,%d,%d,0,0,", globStr, base, req->Width, req->Height);
  1462.     if (ng) fprintf (file, "%s_gad,", base);
  1463.     else    fprintf (file, "NULL,");
  1464.     if (nb) fprintf (file, "%s_brd,", base);
  1465.     else    fprintf (file, "NULL,");
  1466.     if (nt) fprintf (file, "%s_txt,", base);
  1467.     else    fprintf (file, "NULL,");
  1468.     fprintf (file, "0,0,\n\tNULL,{NULL},NULL,NULL,{NULL}\n};\n");
  1469.  
  1470.     fclose (file);
  1471. }
  1472.  
  1473.  
  1474. MemError ()
  1475. {
  1476.     fprintf (stderr, "Out of memory.\n");
  1477. }
  1478.  
  1479.  
  1480. /* Main entry point.  Decode args and call body function.  Args are:
  1481.  *
  1482.  *    -p    : Print box description
  1483.  *    -q    : Run silent, run deep
  1484.  *    -v    : Verbose (not much different than normal, really)
  1485.  *    -d    : Display preview (is default unless output requested)
  1486.  *    -s    : Send Requester declarations to stdout
  1487.  */
  1488. main (argc, argv)
  1489.     int             argc;
  1490.     char           *argv[];
  1491. {
  1492.     int    i, junk = 0, prev = 0, tostdout = 0;
  1493.     char    *infile = NULL, *outfile = NULL;
  1494.  
  1495.     /*
  1496.      * Decode arguments.
  1497.      */
  1498.     for (i = 1; i < argc; i++) {
  1499.         if (argv[i][0] == '-') {
  1500.             switch (argv[i][1]) {
  1501.                 case 'p':
  1502.                 printBoxes = 1;
  1503.                 break;
  1504.                 case 'q':
  1505.                 infoLevel = 0;
  1506.                 break;
  1507.                 case 'v':
  1508.                 infoLevel = 2;
  1509.                 break;
  1510.                 case 'd':
  1511.                 prev = 1;
  1512.                 break;
  1513.                 case 's':
  1514.                 tostdout = 1;
  1515.                 break;
  1516.                 case 'g':
  1517.                 globStr = "";
  1518.                 break;
  1519.                 default:
  1520.                 junk = 1;
  1521.             }
  1522.         } else {
  1523.             if (!infile) infile = argv[i];
  1524.               else if (!outfile) outfile = argv[i];
  1525.               else junk = 1;
  1526.         }
  1527.     }
  1528.     if (junk || !infile) {
  1529.         printf ("Usage: %s [-p|q|v|d|s|g] <file> [<outfile>]\n",
  1530.             argv[0]);
  1531.         exit (1);
  1532.     }
  1533.     if (tostdout) {
  1534.         outfile = "*";
  1535.         infoLevel = 0;
  1536.     }
  1537.     showPreview = (!outfile || prev);
  1538.  
  1539.     if (IntuitionBase = (struct IntuitionBase *)
  1540.         OpenLibrary ("intuition.library", 0L)) {
  1541.         Body (infile, outfile);
  1542.         CloseLibrary (IntuitionBase);
  1543.     }
  1544. }
  1545.  
  1546.  
  1547. Body (infile, outfile)
  1548.     char           *infile, *outfile;
  1549. {
  1550.     struct Window  *win;
  1551.     struct Box     *b;
  1552.     short           h, w;
  1553.  
  1554.     if (infoLevel > 0) printf (
  1555.         "Requester generator v2   Jan 1989  Stuart Ferguson\n");
  1556.     if (!OpenLexFile (infile)) {
  1557.         fprintf (stderr, "Cannot open %s\n", infile);
  1558.         return;
  1559.     }
  1560.     if (b = ReadFile ()) {
  1561.         Format (b);
  1562.         b->x = b->y = 0;
  1563.         Layout (b, b->xs, b->ys);
  1564.         if (printBoxes) PrintBox (b, 0);
  1565.  
  1566.         if (CreateIText (b)) {
  1567.             if (CreateBorder (b)) {
  1568.                 MergeBorders ();
  1569.                 MergeLinear ();
  1570.                 PositionGadgets ();
  1571.  
  1572.                 mreq.Width = b->xs;
  1573.                 mreq.Height = b->ys;
  1574.                 mreq.ReqGadget = glst;
  1575.                 mreq.ReqText = itlst;
  1576.                 mreq.ReqBorder = blst;
  1577.  
  1578.                 if (showPreview) PreviewRequester (&mreq);
  1579.                 if (outfile) WriteRequester (outfile, &mreq);
  1580.  
  1581.                 FreeBorder ();
  1582.             }
  1583.             FreeIText ();
  1584.         }
  1585.         FreeBox (b);
  1586.     } else fprintf (stderr, "Error reading box description.\n");
  1587.     LexCleanup ();
  1588. }
  1589.  
  1590.  
  1591. /*
  1592.  * Open a window to preview the requester layout.
  1593.  */
  1594. PreviewRequester (req)
  1595.     struct Requester *req;
  1596. {
  1597.     struct Window  *win;
  1598.     short           h, w;
  1599.  
  1600.     w = req->Width + 12;
  1601.     h = req->Height + 16;
  1602.     if (w > 640 || h > 200) {
  1603.         fprintf (stderr, "Requester too large for preview.\n");
  1604.         return;
  1605.     }
  1606.     if (w < 150) w = 150;
  1607.     if (h < 60) h = 60;
  1608.  
  1609.     nwin.Width = w;
  1610.     nwin.Height = h;
  1611.     if (!(win = OpenWindow (&nwin))) {
  1612.         fprintf (stderr, "Unable to open preview window.\n");
  1613.         return;
  1614.     }
  1615.  
  1616.     req->LeftEdge =
  1617.         (w - win->BorderRight + win->BorderLeft - req->Width) / 2;
  1618.     req->TopEdge =
  1619.         (h - win->BorderBottom + win->BorderTop - req->Height) / 2;
  1620.  
  1621.     RequesterLoop (win, req);
  1622.     CloseWindow (win);
  1623. }
  1624.  
  1625.  
  1626. RequesterLoop (win, req)
  1627.     struct Window *win;
  1628.     struct Requester *req;
  1629. {
  1630.     struct Gadget *g;
  1631.     struct IntuiMessage *im;
  1632.     ULONG class, oldflags;
  1633.     USHORT code;
  1634.     int gend = 0, looping;
  1635.  
  1636.     /*
  1637.      * Determine if this requester can be terminated with a gadget.
  1638.      * If not, provide an alternate exit facility.
  1639.      */
  1640.     for (g = req->ReqGadget; g; g = g->NextGadget)
  1641.         if (g->Activation & ENDGADGET) {
  1642.             gend = 1;
  1643.             break;
  1644.         }
  1645.     oldflags = req->Flags;
  1646.     if (!gend) {
  1647.         if (infoLevel > 0) printf (
  1648.             "No Endgadget -- Press ESC to exit Requester.\n");
  1649.         req->Flags |= NOISYREQ;
  1650.     }
  1651.  
  1652.     if (!Request (req, win)) {
  1653.         fprintf (stderr, "Unable to post Requester.\n");
  1654.         req->Flags = oldflags;
  1655.         return;
  1656.     }
  1657.  
  1658.     looping = 1;
  1659.     while (looping) {
  1660.         im = (struct IntuiMessage *) GetMsg(win->UserPort);
  1661.         if (!im) {
  1662.             WaitPort (win->UserPort);
  1663.             continue;
  1664.         }
  1665.         class = im->Class;
  1666.         code = im->Code;
  1667.         ReplyMsg (im);
  1668.         if (class == VANILLAKEY && code == 27) break;
  1669.         if (infoLevel > 0) printf ("Message : %s\n", IMClass (class));
  1670.         if (class == REQCLEAR) looping = 0;
  1671.     }
  1672.     if (looping) EndRequest (req, win);
  1673.     req->Flags = oldflags;
  1674. }
  1675.  
  1676.  
  1677. /*
  1678.  * Returns name of message class.  Lots more classes here than are
  1679.  * possible, but what the hell.
  1680.  */
  1681. char * IMClass (class)
  1682.     ULONG class;
  1683. {
  1684.     switch (class) {
  1685.         case SIZEVERIFY:    return ("SIZEVERIFY");
  1686.         case NEWSIZE:    return ("NEWSIZE");
  1687.         case REFRESHWINDOW:    return ("REFRESHWINDOW");
  1688.         case MOUSEBUTTONS:    return ("MOUSEBUTTONS");
  1689.         case MOUSEMOVE:    return ("MOUSEMOVE");
  1690.         case GADGETDOWN:    return ("GADGETDOWN");
  1691.         case GADGETUP:    return ("GADGETUP");
  1692.         case REQSET:    return ("REQSET");
  1693.         case MENUPICK:    return ("MENUPICK");
  1694.         case CLOSEWINDOW:    return ("CLOSEWINDOW");
  1695.         case RAWKEY:    return ("RAWKEY");
  1696.         case REQVERIFY:    return ("REQVERIFY");
  1697.         case REQCLEAR:    return ("REQCLEAR");
  1698.         case MENUVERIFY:    return ("MENUVERIFY");
  1699.         case NEWPREFS:    return ("NEWPREFS");
  1700.         case DISKINSERTED:    return ("DISKINSERTED");
  1701.         case DISKREMOVED:    return ("DISKREMOVED");
  1702.         case WBENCHMESSAGE:    return ("WBENCHMESSAGE");
  1703.         case ACTIVEWINDOW:    return ("ACTIVEWINDOW");
  1704.         case INACTIVEWINDOW:    return ("INACTIVEWINDOW");
  1705.         case DELTAMOVE:    return ("DELTAMOVE");
  1706.         case VANILLAKEY:    return ("VANILLAKEY");
  1707.         case INTUITICKS:    return ("INTUITICKS");
  1708.     }
  1709. }
  1710.  
  1711.  
  1712. #define DEBUG
  1713.  
  1714. /*
  1715.  * Debug routines.
  1716.  */
  1717. #ifdef DEBUG
  1718.  
  1719. PrintBorder ()
  1720. {
  1721.     struct Border *b;
  1722.     short i;
  1723.  
  1724.     printf ("Borders:\n");
  1725.     for (b=blst; b; b=b->NextBorder) {
  1726.         printf ("%d %d %d %d\n:: ", b->LeftEdge,
  1727.             b->TopEdge, b->FrontPen, b->Count);
  1728.         for (i=0; i<b->Count; i++)
  1729.             printf ("%d,%d ", b->XY[i*2],b->XY[i*2+1]);
  1730.         printf ("\n");
  1731.     }
  1732. }
  1733.  
  1734.  
  1735. PrintGadget ()
  1736. {
  1737.     USHORT        typ;
  1738.     struct Gadget    *g;
  1739.  
  1740.     printf ("Gadgets:\n");
  1741.     for (g=glst; g; g=g->NextGadget) {
  1742.         printf ("%d,%d %d,%d  ", g->LeftEdge, g->TopEdge,
  1743.             g->Width, g->Height);
  1744.         typ = GTYPE(g);
  1745.         if (typ == PROPGADGET)    printf ("PROP");
  1746.         if (typ == STRGADGET)    printf ("STRING");
  1747.         if (typ == BOOLGADGET)    printf ("BOOL");
  1748.         printf ("\n");
  1749.     }
  1750. }
  1751. #endif
  1752.